require 'matrix'
require 'open-uri'
require 'hpricot'

class Matrix
  def []=(i,j,x)
    @rows[i][j]=x
  end
end

class String
  def strip_with_full_size_space!
    s = "　\s\v"
    sub!(/^[#{s}]*([^#{s}]+)[#{s}]*$/o, '\1')
  end
  def strip_with_full_size_space
    clone.strip_with_full_size_space!
  end
end


class TopController < ApplicationController

  #before_filter :login_required

  def index
    
  end

  def data
    
    #p "パラメータ"
    #p params[:center_cell_id]
    #p params[:clicked_axis_id]
    #p params[:moving_axis_no]
    #p params[:query].to_s

    #パラメータの設定
    if params[:center_cell_id] != ""
      center_cell_id = params[:center_cell_id].to_i #中心のcellId
    end
    if params[:clicked_axis_id] == ""
      clicked_axis_id = 0
    else
      clicked_axis_id = params[:clicked_axis_id].to_s #現在の軸Id
    end
    if params[:dist_from_focus] == ""
      dist_from_focus = 0
    else
      dist_from_focus = params[:dist_from_focus].to_i #focus軸からの距離
    end
    if params[:focus_axis_id] == ""
      focus_axis_id = 0
    else
      focus_axis_id = params[:focus_axis_id].to_s #出版社軸などは最初に文字が入るのでstring
    end

    if params[:query] == nil
      query = nil
    else
      query = params[:query].strip_with_full_size_space
    end

 
    if ((params[:order] == nil) || (params[:order] == ""))
      order = nil
    else
      order = params[:order].split(/_/)
    end
    
    if params[:submit] == "true"
      submit = true
    else
      submit = false
    end

    author_hold = Array.new()
    publisher_hold = Array.new()
    genre_hold = Array.new()
    query_hold = Array.new()

    hold_hash = Hash.new()
    if params[:hold] != "" and params[:hold] != nil
      holds = params[:hold].split(/_/) #現在動いている軸No
      holds.each{|hold|
        if /^A.*/ =~ hold
          hold.gsub!(/^A/,"")
          author_hold.push(hold)
        elsif /^P.*/ =~ hold
          hold.gsub!(/^P/,"")
          publisher_hold.push(hold)
        elsif /^G.*/ =~ hold
          hold.gsub!(/^G/,"")
          genre_hold.push(hold)
        elsif /^Q.*/ =~ hold
          hold.gsub!(/^Q/,"")
          query_hold.push(hold)
        else
          hold_no = hold.to_i
          hold_hash[hold_no] = true
        end
      }
    end
    hold_hash['A'] = author_hold
    hold_hash['P'] = publisher_hold
    hold_hash['G'] = genre_hold
    hold_hash['Q'] = query_hold

    if center_cell_id == nil
      #Nilなら初期表示
      #Queryの内容によって処理を変更
      if query == nil
        #売り上げ最新を取得
        center_cell = AsinInfo.find(:first,
          :order => 'sales_rank asc',
          :conditions => ['sales_rank != ? and sales_rank is not null and contents_type = 0',0]
          #:from => "asin_infos use index (index_asin_infos_on_sales_rank)"
        )
      else
        #キーワードに該当するものトップ
        center_cell = AsinInfo.search_by_title(query)
        result = center_cell
      end
    else
      #中心IDがあった
      if query == nil
        #キーワードなしで辿っている
        center_cell = AsinInfo.find(center_cell_id)
      else
        if submit
          result = AsinInfo.include_by_title_and_id?(query,center_cell_id)
          if result
            center_cell = result
          else
            center_cell = AsinInfo.search_by_title(query)
            result = center_cell
          end
        else
          #キーワード軸はあるが、他の軸で辿っている
          center_cell = AsinInfo.find(center_cell_id)
          result = center_cell
        end
      end
      
      #center_cell = AsinInfo.find(34727)
    end

    #軸オブジェクトの生成
    output_axes = Array.new

    axis_rank = [
       [
       # ダミー軸のID
       99,
       # コード片
       Proc.new{|center_cell,hold_hash|
         #ダミー軸の作成
         publication_date_rank_axis = ZzBookAxis.new(center_cell,query)
         publication_date_rank_axis.make_dummy_axis(hold_hash)
         output_axes.push(publication_date_rank_axis)
        },
        # 軸ランク
        0.0
      ],

      [
        # 検索軸のID
        11,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #クリック数軸の作成
          #p query
          unless (query == nil) or (query == "")
            if AsinInfo.include_by_title_and_id?(query,result.id)
              p "make_query_axis"
              search_axis = ZzBookAxis.new(center_cell,query)
              search_axis.make_query_axis(hold_hash)
              output_axes.push(search_axis)
            end
          end
        },
        # 軸ランク
        0.0
      ],
      [
        # 著者軸のID
        0,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #著者軸の生成
          if center_cell.author_id != nil
            author_axis = ZzBookAxis.new(center_cell,query)
            author_axis.make_author_axis(hold_hash)
            output_axes.push(author_axis)
          end
        },
        # 軸ランク
        0.0
      ],
      [
        # ジャンル軸のID
        10,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #ページ数軸の作成
          if center_cell.genre != nil
            genre_axis = ZzBookAxis.new(center_cell,query)
            genre_axis.make_genre_axis(hold_hash)
            output_axes.push(genre_axis)
          end
        },
        # 軸ランク
        0.0
      ],
      [
        # 売上軸のID
        3,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #売り上げ軸の生成
          #売り上げ軸の生成
          if center_cell.sales_rank != nil
            sales_rank_axis = ZzBookAxis.new(center_cell,query)
            sales_rank_axis.make_sales_rank_axis(hold_hash)
            output_axes.push(sales_rank_axis)
          end
        },
        # 軸ランク
        0.0
      ],
      [ 
        # 出版社軸のID
        2,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #出版社軸の生成
          if center_cell.publisher_id != nil
            publisher_axis = ZzBookAxis.new(center_cell,query)
            publisher_axis.make_publisher_axis(hold_hash)
            output_axes.push(publisher_axis)
          end
        },
        # 軸ランク
        0.0
      ],
      [ 
        #おすすめ軸のID
        1,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #おすすめ軸の作成
          similarity_axis = ZzBookAxis.new(center_cell,query)
          if similarity_axis.make_similarity_axis(hold_hash)
            output_axes.push(similarity_axis)
          end
        },
        # 軸ランク
        0.0
      ],
      [ 
        # レビュー軸のID
        4,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #レビュー数軸の作成
          if center_cell.total_reviews_rank != nil
            total_reviews_rank_axis = ZzBookAxis.new(center_cell,query)
            total_reviews_rank_axis.make_total_reviews_rank_axis(hold_hash)
            output_axes.push(total_reviews_rank_axis)
          end
        },
        # 軸ランク
        0.0
      ],
      [ 
        # 平均評価レート軸のID
        5,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #平均評価レート軸の作成
          if center_cell.average_rating_rank != nil
            average_rating_rank_axis = ZzBookAxis.new(center_cell,query)
            average_rating_rank_axis.make_average_rating_rank_axis(hold_hash)
            output_axes.push(average_rating_rank_axis)
          end
        },
        # 軸ランク
        0.0
      ],
      [ 
        # 価格軸のID
        6,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #価格軸の作成
          if center_cell.price_rank != nil
            price_rank_axis = ZzBookAxis.new(center_cell,query)
            price_rank_axis.make_price_rank_axis(hold_hash)
            output_axes.push(price_rank_axis)
          end
        },
        # 軸ランク
        0.0
      ],
      [ 
        # ページ数軸のID
        7,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #ページ数軸の作成
          if center_cell.number_ofpages_rank != nil
            number_ofpages_rank_axis = ZzBookAxis.new(center_cell,query)
            number_ofpages_rank_axis.make_number_ofpages_rank_axis(hold_hash)
            output_axes.push(number_ofpages_rank_axis)
          end
        },
        # 軸ランク
        0.0
      ],

      [
        # 出版日軸のID
        8,
        # コード片
        Proc.new{|center_cell,hold_hash|
          #出版日軸の作成
          if center_cell.publication_date_rank != nil
            publication_date_rank_axis = ZzBookAxis.new(center_cell,query)
            publication_date_rank_axis.make_publication_date_rank_axis(hold_hash)
            output_axes.push(publication_date_rank_axis)
          end
        },
        # 軸ランク
        0.0
      ]
      #[
      #  # クリック数軸のID
      #  9,
      #  # コード片
      #  Proc.new{|center_cell,hold_hash|
      #    #クリック数軸の作成
      #    if center_cell.number_ofclicks_rank != 0
      #      number_ofclicks_rank_axis = ZzBookAxis.new(center_cell,query)
      #      number_ofclicks_rank_axis.make_number_ofclicks_rank_axis(hold_hash)
      #      output_axes.push(number_ofclicks_rank_axis)
      #    end
      #  },
      #  # 軸ランク
      #  0.0
      #]

    ]

    if order == nil
      #軸ランクを元にソート
      axis_rank.sort! { |a,b|
        b[2] <=> a[2]
      }
    else
      p order
      #クライアントから送られた順
      tmp_axis_rank = Array.new
      
      #orderの中にQが入っていなくてクエリが存在したならば先頭に入れる
      order_have_query = false
      order.each{|aid|
        if (/^Q.*/ =~ aid)
          order_have_query = true
          break
        end
      }
      if (!((query == nil) or (query == "")) and !order_have_query) 
        tmp_axis_rank << axis_rank[1]
      end
            
      order.each{|aid|
        axis_rank.each{|axis|
          if axis[0] == 99 && axis
            # break
          elsif (axis[0].to_s == aid)
            tmp_axis_rank << axis
            break
          elsif (/^A.*/ =~ aid && axis[0] == 0)
            tmp_axis_rank << axis
            break
          elsif (/^G.*/ =~ aid && axis[0] == 10)
            tmp_axis_rank << axis
            break
          elsif (/^P.*/ =~ aid && axis[0] == 2)
            tmp_axis_rank << axis
            break
          elsif (/^Q.*/ =~ aid && axis[0] == 11)
            tmp_axis_rank << axis
            break
          else
          end
        }
      }
      
      #orderに含まれていない軸を入れる
      order_ids = Array.new
      order.each{|aid|
        if (/^A.*/ =~ aid)
          order_ids << 0
        elsif (/^G.*/ =~ aid)
          order_ids << 10
        elsif (/^P.*/ =~ aid)
          order_ids << 2
        elsif (/^Q.*/ =~ aid)
          order_ids << 11
        else
          order_ids << aid.to_i
        end
      }
      axis_rank.each{|axis|
        unless order_ids.include?(axis[0])
          tmp_axis_rank << axis
        end
      }
      
      tmp_axis_rank.unshift(axis_rank[0])
      
      axis_rank = tmp_axis_rank
      
      p tmp_axis_rank
   
    end

    axis_rank.each{|axis|
      code = axis[1]
      code.call(center_cell,hold_hash)
    }



    #ログインしていない場合はanonymousでデータを保存
    #ログインしていない場合はanonymousでデータを保存
    begin
      current_user_id = current_user.id
    rescue
      current_user_id = User.find(:first,
        :conditions => ["login = ?","anonymous"]
      ).id
    end


    markov = Matrix.zero(9)
    #logs = Log.find(:all,
    # :conditions => ["stype = ? and user_id = ?","1",current_user_id],
    # :order => 'created_at'
    #)

    last_index = nil
=begin
    logs.each{|log|
      next if log.stype != 1
      axis_id = log.axis_id
      if  /^A/ =~ axis_id.to_s
        # 著者軸
        unless last_index == nil
          markov[last_index,0] +=1.0
        end
        last_index = 0
      elsif axis_id == 1.to_s
        # ジャンル
        unless last_index == nil
          markov[last_index,1] +=1.0
        end
        last_index = 1
      elsif axis_id == 2.to_s
        # 売上
        unless last_index == nil
          markov[last_index,2] +=1.0
        end
        last_index = 2
      elsif  /^P/ =~ axis_id.to_s
        # 出版社軸
        unless last_index == nil
          markov[last_index,3] +=1.0
        end
        last_index = 3
      elsif  axis_id == 4.to_s
        # おすすめ軸
        unless last_index == nil
          markov[last_index,4] +=1.0
        end
        last_index = 4
      elsif  axis_id == 5.to_s
        # レビュー数軸
        unless last_index == nil
          markov[last_index,5] +=1.0
        end
        last_index = 5
      elsif  axis_id == 6.to_s
        # レート
        unless last_index == nil
          markov[last_index,6] +=1.0
        end
        last_index = 6
      elsif axis_id == 7.to_s
        # 価格
        unless last_index == nil
          markov[last_index,7] +=1.0
        end
        last_index = 7
      elsif axis_id == 8.to_s
        # ページ数
        unless last_index == nil
          markov[last_index,8] +=1.0
        end
        last_index = 8
      elsif axis_id == 9.to_s
        # ページ数
        unless last_index == nil
          markov[last_index,9] +=1.0
        end
        last_index = 9
      elsif axis_id == 10.to_s
        # ページ数
        unless last_index == nil
          markov[last_index,10] +=1.0
        end
        last_index = 10
      end
    }
=end
    p markov

    new_markov = Array.new
    (0..markov.row_size-1).each{|i|
      row_vector = Array.new
      sum = 0
      markov.row(i).collect{|j|
        sum += j
      }
      if sum == 0.0
        row_vector.fill(1.0/markov.column_size,0..markov.column_size-1)
      else
        markov.row(i).collect{|k|
          row_vector << k/sum
        }
      end
      new_markov << row_vector
    }
    #[行1,行2,…]と入れるべきらしいので１段崩す
    markov = Matrix[*new_markov]
    p markov

    #p output_axes
    #p clicked_axis_id
    #moving_axis_no番目のカテゴリがclicked_axis_idになるまでunshift,pushを繰り返す
    #while output_axes[moving_axis_no]['axisid'] != clicked_axis_id.to_i
    #  shist_axis = output_axes.shift
    #  output_axes << shist_axis
    #end

    move_axis_index = 0
    output_axes.each_with_index{|axis,i|
      if axis['axisid'].to_s == clicked_axis_id.to_s
        move_axis_index = i
      end
    }
    focus_index = move_axis_index - dist_from_focus
    if focus_index < 0
      focus_index = 0
    end
    output_axes[focus_index]['is_focus'] = true
    
    @output = output_axes

    respond_to do |format|
      format.json { render :json=>@output}
    end
  end

  def click
    cid = params[:cid] #クリックされたコンテンツのId
    AsinInfo.connection.execute("UPDATE asin_infos SET number_ofclicks = LAST_INSERT_ID(number_ofclicks + 1) WHERE id = " + cid + ";")
  end

  def log
    log_type = params[:log_type]
    local_log = Log.new(:log_type => log_type,:user_id => get_current_user_id)
    local_log.save
    log_id = Log.find(:first,:order => 'id desc')
    render :text => log_id.id.to_s
  end

  def mouseover_cells_log
    log_id = params[:log_id]
    asin_info_id = params[:asin_info_id]
    mcl = MouseoverCellsLog.new(:log_id => log_id, :asin_info_id => asin_info_id)
    mcl.save
    render :text => ""
  end

  def click_bookinfo_log
    log_id = params[:log_id]
    asin_info_id = params[:asin_info_id]
    mcl = ClickBookinfoLog.new(:log_id => log_id, :asin_info_id => asin_info_id)
    mcl.save
    render :text => ""
  end

  def click_cells_log
    log_id = params[:log_id]
    asin_info_id = params[:asin_info_id]
    mcl = ClickBookinfoLog.new(:log_id => log_id, :asin_info_id => asin_info_id)
    mcl.save
    render :text => ""
  end

  def search_log
    log_id = params[:log_id]
    query = params[:query]
    query.strip_with_full_size_space!
    q = Query.find(:first,:conditions => {:query => query})
    if q == nil
      q = Query.new({:query => query})
      q.save
      q = Query.find(:first,:order => "id desc")
    end
    slg = SearchLog.new(:log_id => log_id, :query_id => q.id)
    slg.save
    render :text => ""
  end

  def change_axis_log
    log_id = params[:log_id]
    axis_id = params[:axis_id]
    axis_combination_string = params[:axis_combination]
    axis_combination = axis_combination_string.split("_")
    csal = CreateShowAxisLog.new(
                                  :log_id => log_id,
                                  :axis_id_1 => axis_combination[0],
                                  :axis_hold_1 => axis_combination[1],
                                  :axis_id_2 => axis_combination[2],
                                  :axis_hold_2 => axis_combination[3],
                                  :axis_id_3 => axis_combination[4],
                                  :axis_hold_3 => axis_combination[5]
                                  )
    csal.save
    cal = ChangeAxisLog.new(:log_id => log_id, :axis_id => axis_id)
    cal.save
    render :text => ""
  end

  def slide_axis_log
    log_id = params[:log_id]
    axis_id = params[:axis_id]
    direction = params[:direction]
    cal = SlideAxisLog.new(:log_id => log_id, :axis_id => axis_id, :direction => direction)
    cal.save
    render :text => ""
  end

  def move_center_cells_log
    log_id = params[:log_id]
    asin_infos_id = params[:asin_infos_id]
    cal = MoveCenteCellsLog.new(:log_id => log_id, :axis_infos_id => asin_infos_id)
    cal.save
    render :text => ""
  end


  def description
    cid = params[:cid].to_i
    book = AsinInfo.find(cid)
    doc = Hpricot(open(book.detail_page_url))
    text = (doc/"div.productDescriptionWrapper").first.inner_html
    render :text => Kconv.kconv(text, Kconv::UTF8, Kconv::AUTO)
  end

  def new
  end

  def destroy
    logout_killing_session!
    flash[:notice] = "You have been logged out."
    redirect_back_or_default root_url
  end

  private
  def get_current_user_id
    #ログインしていない場合はanonymousでデータを保存
    begin
      current_user_id = current_user.id
    rescue
      current_user_id = User.find(:first,
        :conditions => ["login = ?","anonymous"]
      ).id
    end
    return current_user_id
  end

end
